package MicroSpring.beanPostProcessor.impl;

import MicroSpring.annotation.Autowired;
import MicroSpring.annotation.Lazy;
import MicroSpring.annotation.Value;
import MicroSpring.beanFactory.impl.DefaultListableBeanFactory;
import MicroSpring.beanPostProcessor.InstantiationAwareBeanPostProcessor;
import MicroSpring.beanPostProcessor.metadata.InjectionMetadata;
import MicroSpring.common.BeanUtils;
import MicroSpring.common.SymbolResovler;

import java.lang.reflect.*;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;

/*
    @Autowired   @Value
    这里暂时直接实现InstantiationAwareBeanPostProcessor
 */
public class AutowiredAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    private final DefaultListableBeanFactory beanFactory;

    public AutowiredAnnotationBeanPostProcessor(DefaultListableBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    /**
     * *查找哪些属性，方法加了那俩注解
     * @param beanName
     * @param clazz
     * @return
     */
    private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz){
        InjectionMetadata metadata=new InjectionMetadata(beanFactory);
        metadata.setTargetClass(clazz);
        Field[] declaredFields = clazz.getDeclaredFields();
        Collection<InjectionMetadata.InjectedElement>injectedElements=new HashSet<>();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            Value value = field.getAnnotation(Value.class);
            InjectionMetadata.InjectedElement  injectedElement=null;
            if (value !=null){
                injectedElement=new InjectionMetadata.InjectedElement();
                injectedElement.setField(field);
                injectedElement.setVals(SymbolResovler.getResovleStringFromResource(value.value()));
            }
            Autowired autowired = field.getAnnotation(Autowired.class);
            if (autowired!=null){
                beanFactory.addBeansInjectBeans(beanName,field);
                if (field.isAnnotationPresent(Lazy.class)){
                    if (BeanUtils.checkLazyBean(field.getType())){
                        beanFactory.addLazyInjectBeans(beanName,field);
                        continue;
                    }
                }
                if (injectedElement==null)
                    injectedElement=new InjectionMetadata.InjectedElement();
                injectedElement.setField(field);
                injectedElement.setInjectClazz(field.getType());
            }
            if (injectedElement!=null)
                injectedElements.add(injectedElement);
        }

        //处理方法上的注解注入
        //解析${} 获取配置文件的值,并且将其赋给value属性
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            if (method.getParameters().length>0){
                for (Parameter parameter : method.getParameters()) {
                    if (parameter.isAnnotationPresent(Value.class)){
                        Value annotation = parameter.getDeclaredAnnotation(Value.class);
                        //修改注解的属性值 : 通过代理获取它的memberValues字段,里面藏着这些属性值
                        String key = annotation.value();
                        InvocationHandler h = Proxy.getInvocationHandler(annotation);
                        Field f = null;
                        try {
                            f = h.getClass().getDeclaredField("memberValues");
                            f.setAccessible(true);
                            Map<String,Object> mp = (Map<String, Object>) f.get(h);
                            mp.put("value", SymbolResovler.getResovleStringFromResource(key));
                            //将解析的结果赋给该注解，等待后续的处理
                            beanFactory.addDealingInjectMethods(beanName,method);
                        } catch (NoSuchFieldException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        metadata.setInjectedElements(injectedElements);
        return metadata;
    }




    private void resolveValueAnnotation(Class beanClazz, Object o2) {
        Field[] declaredFields = beanClazz.getDeclaredFields();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            Value value = field.getAnnotation(Value.class);
            if (value !=null){
                String value1 = value.value();
                try {
                    field.set(o2,value1);
                } catch (IllegalAccessException e) {
                    System.out.println((LocalDateTime.now().toLocalTime()) +"【处理value值注入异常】");
                    e.printStackTrace();
                }
            }
        }
    }

    /*
        依赖注入阶段
     */
    @Override
    public void postProcessProperties(Object bean, String beanName) {
        InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass());
        try {
            metadata.inject(bean,beanName);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }


}
